home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 37 / IOPROG_37.ISO / SOFT / Multilizer.exe / disk1 / data1.cab / data1 / [Group19]VCL Source Professional / IvDateTi.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-01-27  |  24.8 KB  |  1,071 lines

  1. unit IvDateTi;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls, IvButtons, Menus, IvDictio;
  8.  
  9. type
  10.   TIvCalendarButton = class(TIvFrameButton)
  11.   public
  12.     constructor Create(AOwner: TComponent); override;
  13.   end;
  14.  
  15.   TIvCalendarGrid = class(TGraphicControl)
  16.   private
  17.     FDate: TDateTime;
  18.     FFirstDate: TDateTime;
  19.     FColCount: Integer;
  20.     FColWidth: Integer;
  21.     FRowCount: Integer;
  22.     FRowHeight: Integer;
  23.     FOldPos: TPoint;
  24.     FTracking: Boolean;
  25.     FOnChange: TNotifyEvent;
  26.     FOnSelect: TNotifyEvent;
  27.  
  28.     function GetDay: Word;
  29.     function GetMonth: Word;
  30.     function GetYear: Word;
  31.     function GetWeek: Word;
  32.     function GetWeeks(row: Integer): Integer;
  33.     function GetDates(col, row: Integer): TDateTime;
  34.  
  35.     procedure SetDay(value: Word);
  36.     procedure SetMonth(value: Word);
  37.     procedure SetYear(value: Word);
  38.     procedure SetWeek(value: Word);
  39.     procedure SetDate(value: TDateTime);
  40.  
  41.     function CellAt(x, y: Integer): TPoint;
  42.     function CellRect(col, row: Integer): TRect;
  43.     function AcceptCell(col, row: Integer): Boolean;
  44.     procedure ToggleCell(col, row: Integer);
  45.  
  46.   protected
  47.     function GetLocaleData: TIvLocale;
  48.  
  49.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  50.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  51.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  52.  
  53.     procedure Paint; override;
  54.  
  55.   public
  56.     constructor Create(AOwner: TComponent); override;
  57.  
  58.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  59.  
  60.     property Day: Word read GetDay write SetDay;
  61.     property Month: Word read GetMonth write SetMonth;
  62.     property Year: Word read GetYear write SetYear;
  63.     property Week: Word read GetWeek write SetWeek;
  64.     property Date: TDateTime read FDate write SetDate;
  65.     property Weeks[row: Integer]: Integer read GetWeeks;
  66.     property Dates[col, row: Integer]: TDateTime read GetDates;
  67.  
  68.   protected
  69.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  70.     property OnSelect: TNotifyEvent read FOnSelect write FOnSelect;
  71.   end;
  72.  
  73.   TIvCalendar = class(TCustomControl)
  74.   private
  75.     FMargin: Integer;
  76.     FPriorMonth: TIvCalendarButton;
  77.     FNextMonth: TIvCalendarButton;
  78.     FPriorYear: TIvCalendarButton;
  79.     FNextYear: TIvCalendarButton;
  80.     FMonth: TLabel;
  81.     FMonthMenu: TPopupMenu;
  82.     FYear: TLabel;
  83.     FToday: TLabel;
  84.     FTodayCaption: String;
  85.     FGrid: TIvCalendarGrid;
  86.     FOnSelect: TNotifyEvent;
  87.  
  88.     function GetDate: TDateTime;
  89.     function GetWeek: Integer;
  90.  
  91.     procedure SetTodayCaption(const value: String);
  92.     procedure SetDate(value: TDateTime);
  93.     procedure SetWeek(value: Integer);
  94.  
  95.     procedure PriorMonthClick(Sender: TObject);
  96.     procedure NextMonthClick(Sender: TObject);
  97.     procedure PriorYearClick(Sender: TObject);
  98.     procedure NextYearClick(Sender: TObject);
  99.     procedure MonthClick(Sender: TObject);
  100.     procedure MonthMenuClick(Sender: TObject);
  101.     procedure TodayClick(Sender: TObject);
  102.     procedure ValueChange(Sender: TObject);
  103.     procedure ValueSelect(Sender: TObject);
  104.  
  105.   protected
  106.     procedure Paint; override;
  107.  
  108.   public
  109.     constructor Create(AOwner: TComponent); override;
  110.  
  111.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  112.  
  113.     property Date: TDateTime read GetDate write SetDate;
  114.     property Week: Integer read GetWeek write SetWeek;
  115.  
  116.   published
  117.     //property Width default 100;
  118.     //property Height default 100;
  119.     property TodayCaption: String read FTodayCaption write SetTodayCaption;
  120.     property OnSelect: TNotifyEvent read FOnSelect write FOnSelect;
  121.   end;
  122.  
  123.   TIvDateTimeList = class(TIvCalendar)
  124.   private
  125.     procedure WMMouseActivate(var Message: TMessage); message WM_MOUSEACTIVATE;
  126.  
  127.   protected
  128.     procedure CreateParams(var Params: TCreateParams); override;
  129.  
  130.   public
  131.     constructor Create(AOwner: TComponent); override;
  132.   end;
  133.  
  134.   TIvDateTimeButton = class(TIvFrameButton)
  135.   protected
  136.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  137.  
  138.   public
  139.     constructor Create(AOwner: TComponent); override;
  140.   end;
  141.  
  142.   TIvDateTimeKind = (dtkYear, dtkMonth, dtkWeek, dtkDate, dtkTime);
  143.  
  144.   TIvCustomDateTimeEdit = class(TCustomEdit)
  145.   private
  146.     FButton: TIvFrameButton;
  147.     FKind: TIvDateTimeKind;
  148.     FList: TIvDateTimeList;
  149.     FListVisible: Boolean;
  150.  
  151.     function GetAsDate: TDateTime;
  152.     function GetAsString: String;
  153.     function GetListHeight: Integer;
  154.     function GetListWidth: Integer;
  155.  
  156.     procedure SetAsDate(value: TDateTime);
  157.     procedure SetAsString(const value: String);
  158.     procedure SetKind(value: TIvDateTimeKind);
  159.     procedure SetListHeight(value: Integer);
  160.     procedure SetListWidth(value: Integer);
  161.  
  162.     procedure SetEditRect;
  163.  
  164.     procedure ListSelect(Sender: TObject);
  165.  
  166.     procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  167.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  168.  
  169.   protected
  170.     procedure CreateParams(var Params: TCreateParams); override;
  171.     procedure CreateWnd; override;
  172.  
  173.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  174.     procedure KeyPress(var Key: Char); override;
  175.  
  176.     function AcceptChar(key: Char): Boolean; virtual;
  177.     procedure SelectListValue; virtual;
  178.  
  179.   public
  180.     constructor Create(AOwner: TComponent); override;
  181.  
  182.     procedure DropDown;
  183.     procedure CloseUp(accept: Boolean);
  184.  
  185.     procedure Clear; override;
  186.  
  187.     property AsDate: TDateTime read GetAsDate write SetAsDate;
  188.     property AsString: String read GetAsString write SetAsString;
  189.     property ListVisible: Boolean read FListVisible;
  190.  
  191.   published
  192.     property Kind: TIvDateTimeKind read FKind write SetKind;
  193.     property ListHeight: Integer read GetListHeight write SetListHeight;
  194.     property ListWidth: Integer read GetListWidth write SetListWidth;
  195.   end;
  196.  
  197.   TIvDateTimeEdit = class(TIvCustomDateTimeEdit)
  198.   public
  199.     constructor Create(AOwner: TComponent); override;
  200.   end;
  201.  
  202. { Utils }
  203.  
  204. procedure IvDrawTextRect(
  205.   canvas: TCanvas;
  206.   const text: String;
  207.   rect: TRect;
  208.   alignment: TAlignment);
  209.  
  210. implementation
  211.  
  212. uses
  213.   IvMlUtil;
  214.  
  215. // Utils
  216.  
  217. procedure IvDrawTextRect(
  218.   canvas: TCanvas;
  219.   const text: String;
  220.   rect: TRect;
  221.   alignment: TAlignment);
  222. const
  223.   alignments: array[TAlignment] of Integer = (DT_LEFT, DT_RIGHT, DT_CENTER);
  224. begin
  225.   DrawText(
  226.     canvas.Handle,
  227.     PChar(text),
  228.     StrLen(PChar(text)),
  229.     rect,
  230.     alignments[alignment] or DT_VCENTER or DT_SINGLELINE);
  231. end;
  232.  
  233. procedure DrawTodayMark(canvas: TCanvas; rect: TRect);
  234. begin
  235.   canvas.Pen.Color := clRed;
  236.   canvas.Pen.Style := psSolid;
  237.   canvas.Pen.Width := 2;
  238.   canvas.Brush.Style := bsClear;
  239.   canvas.Ellipse(rect.Left, rect.Top, rect.Right, rect.Bottom);
  240. end;
  241.  
  242.  
  243. // TIvCalendarButton
  244.  
  245. constructor TIvCalendarButton.Create(AOwner: TComponent);
  246. begin
  247.   inherited Create(AOwner);
  248.   Timed := True;
  249.   FrameType := DFC_SCROLL;
  250. end;
  251.  
  252.  
  253. // TIvCalendarGrid
  254.  
  255. constructor TIvCalendarGrid.Create(AOwner: TComponent);
  256. begin
  257.   inherited Create(AOwner);
  258.   FColCount := 8;
  259.   FRowCount := 7;
  260. end;
  261.  
  262. function TIvCalendarGrid.GetDay: Word;
  263. var
  264.   year, month, day: Word;
  265. begin
  266.   DecodeDate(Date, year, month, day);
  267.   Result := day;
  268. end;
  269.  
  270. procedure TIvCalendarGrid.SetDay(value: Word);
  271. var
  272.   year, month, day: Word;
  273. begin
  274.   DecodeDate(Date, year, month, day);
  275.  
  276.   if day <> value then
  277.     Date := EncodeDate(year, month, value);
  278. end;
  279.  
  280. function TIvCalendarGrid.GetMonth: Word;
  281. var
  282.   year, month, day: Word;
  283. begin
  284.   DecodeDate(Date, year, month, day);
  285.   Result := month;
  286. end;
  287.  
  288. procedure TIvCalendarGrid.SetMonth(value: Word);
  289. var
  290.   year, month, day: Word;
  291. begin
  292.   DecodeDate(Date, year, month, day);
  293.  
  294.   if month <> value then
  295.     Date := IncMonth(FDate, value - month);
  296. end;
  297.  
  298. function TIvCalendarGrid.GetYear: Word;
  299. var
  300.   year, month, day: Word;
  301. begin
  302.   DecodeDate(Date, year, month, day);
  303.   Result := year;
  304. end;
  305.  
  306. procedure TIvCalendarGrid.SetYear(value: Word);
  307. var
  308.   year, month, day: Word;
  309. begin
  310.   DecodeDate(Date, year, month, day);
  311.  
  312.   if year <> value then
  313.     Date := EncodeDate(value, month, day);
  314. end;
  315.  
  316. function TIvCalendarGrid.GetLocaleData: TIvLocale;
  317. begin
  318.   Result := IvDictio.GetDefaultDictionary.LocaleData;
  319. end;
  320.  
  321. function TIvCalendarGrid.GetWeek: Word;
  322. begin
  323.   with GetLocaleData do
  324.     Result := IvWeek(FDate, FirstWeekOfYear, FirstDayOfWeek);
  325. end;
  326.  
  327. procedure TIvCalendarGrid.SetWeek(value: Word);
  328. begin
  329. end;
  330.  
  331. procedure TIvCalendarGrid.SetDate(value: TDateTime);
  332. begin
  333.   if FDate <> value then
  334.   begin
  335.     FDate := value;
  336.     with GetLocaleData do
  337.     begin
  338.       FFirstDate := IvFirstDayOfWeek(IvFirstDayOfMonth(FDate), FirstDayOfWeek);
  339.  
  340.       if IvDayOfWeekNumber(IvFirstDayOfMonth(FDate), FirstDayOfWeek) = 1 then
  341.         FFirstDate := FFirstDate - 7;
  342.     end;
  343.  
  344.     if Assigned(FOnChange) then
  345.       FOnChange(Self);
  346.  
  347.     Invalidate;
  348.   end;
  349. end;
  350.  
  351. function TIvCalendarGrid.GetDates(col, row: Integer): TDateTime;
  352. begin
  353.   Result := FFirstDate + (FColCount - 1)*row + col;
  354. end;
  355.  
  356. function TIvCalendarGrid.GetWeeks(row: Integer): Integer;
  357. begin
  358.   with GetLocaleData do
  359.     Result := (IvWeek(FFirstDate, FirstWeekOfYear, FirstDayOfWeek) + row - 1) mod 52 + 1;
  360. end;
  361.  
  362. procedure TIvCalendarGrid.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  363. begin
  364.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  365.   FColWidth := Width div FColCount;
  366.   FRowHeight := Height div FRowCount;
  367. end;
  368.  
  369. function TIvCalendarGrid.CellAt(x, y: Integer): TPoint;
  370. begin
  371.   Result.X := x div FColWidth;
  372.   Result.Y := y div FRowHeight;
  373. end;
  374.  
  375. function TIvCalendarGrid.CellRect(col, row: Integer): TRect;
  376. begin
  377.   Result.Left := col*FColWidth;
  378.   Result.Top := row*FRowHeight;
  379.   Result.Right := Result.Left + FColWidth;
  380.   Result.Bottom := Result.Top + FRowHeight;
  381. end;
  382.  
  383. procedure TIvCalendarGrid.ToggleCell(col, row: Integer);
  384. begin
  385.   DrawFocusRect(Canvas.Handle, CellRect(col, row));
  386. end;
  387.  
  388. function TIvCalendarGrid.AcceptCell(col, row: Integer): Boolean;
  389. begin
  390.   Result := (0 < col) and (col < FColCount) and
  391.     (0 < row) and (row < FRowCount);
  392. end;
  393.  
  394. procedure TIvCalendarGrid.MouseDown(
  395.   Button: TMouseButton;
  396.   Shift: TShiftState;
  397.   X, Y: Integer);
  398. begin
  399.   inherited MouseDown(Button, Shift, X, Y);
  400.  
  401.   if Button = mbLeft then
  402.   begin
  403.     with CellAt(x, y) do
  404.     begin
  405.       if AcceptCell(x, y) then
  406.       begin
  407.         ToggleCell(x, y);
  408.         FOldPos := Point(x, y);
  409.         FTracking := True;
  410.       end;
  411.     end;
  412.   end;
  413. end;
  414.  
  415. procedure TIvCalendarGrid.MouseUp(
  416.   Button: TMouseButton;
  417.   Shift: TShiftState;
  418.   X, Y: Integer);
  419. begin
  420.   inherited MouseUp(Button, Shift, X, Y);
  421.  
  422.   if FTracking then
  423.   begin
  424.     ToggleCell(FOldPos.x, FOldPos.y);
  425.  
  426.     with CellAt(x, y) do
  427.       if AcceptCell(x, y) then
  428.       begin
  429.         Date := Dates[x - 1, y - 1];
  430.  
  431.         if Assigned(FOnSelect) then
  432.           FOnSelect(Self);
  433.       end;
  434.  
  435.     FTracking := False;
  436.   end;
  437. end;
  438.  
  439. procedure TIvCalendarGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
  440. begin
  441.   inherited MouseMove(Shift, X, Y);
  442.  
  443.   if FTracking then
  444.   begin
  445.     with CellAt(x, y) do
  446.       if AcceptCell(x, y) then
  447.       begin
  448.         ToggleCell(FOldPos.x, FOldPos.y);
  449.         ToggleCell(x, y);
  450.         FOldPos := Point(x, y);
  451.       end;
  452.   end;
  453. end;
  454.  
  455. procedure TIvCalendarGrid.Paint;
  456. var
  457.   item: TDateTime;
  458.   year, month, day: Word;
  459.   color: TColor;
  460.   i, j: Integer;
  461.  
  462.   procedure DrawCell(
  463.     col, row: Integer;
  464.     const text: String;
  465.     color: TColor;
  466.     selected: Boolean;
  467.     mark: Boolean);
  468.   var
  469.     cell: TRect;
  470.   begin
  471.     cell := CellRect(col, row);
  472.  
  473.     if selected then
  474.     begin
  475.       Canvas.Pen.Style := psClear;
  476.       Canvas.Brush.Style := bsSolid;
  477.       Canvas.Brush.Color := clNavy;
  478.       Canvas.Rectangle(cell.Left, cell.Top, cell.Right, cell.Bottom);
  479.       Canvas.Font.Color := clWhite;
  480.     end
  481.     else
  482.     begin
  483.       Canvas.Brush.Style := bsClear;
  484.       Canvas.Font.Color := color;
  485.     end;
  486.  
  487.     IvDrawTextRect(Canvas, text, cell, taCenter);
  488.  
  489.     if mark then
  490.       DrawTodayMark(Canvas, cell);
  491.   end;
  492.  
  493. begin
  494.   { Lines }
  495.   Canvas.Pen.Color := clBlack;
  496.   Canvas.Pen.Style := psSolid;
  497.   Canvas.Pen.Width := 1;
  498.   Canvas.MoveTo(0, FRowHeight - 1);
  499.   Canvas.LineTo(Width, FRowHeight - 1);
  500.  
  501.   Canvas.MoveTo(FColWidth - 1, 0);
  502.   Canvas.LineTo(FColWidth - 1, FRowCount*FRowHeight);
  503.  
  504.   { Days of Week }
  505.   Canvas.Brush.Style := bsClear;
  506.   Canvas.Font.Style := [fsBold];
  507.   DrawCell(0, 0, 'no', clNavy, False, False);
  508.   Canvas.Font.Style := [];
  509.  
  510.   for i := 1 to 7 do
  511.     DrawCell(i, 0, ShortDayNames[IvVCLDayToDay(i)], clNavy, False, False);
  512.  
  513.   { Weeks }
  514.   Canvas.Font.Color := clRed;
  515.  
  516.   for i := 1 to FRowCount - 1 do
  517.     DrawCell(0, i, IntToStr(Weeks[i - 1]), clRed, False, False);
  518.  
  519.   { Days }
  520.   Canvas.Font.Color := clBlack;
  521.  
  522.   for j := 1 to FRowCount - 1 do
  523.     for i := 1 to FColCount - 1 do
  524.     begin
  525.       item := Dates[i - 1, j - 1];
  526.       DecodeDate(item, year, month, day);
  527.       color := clSilver;
  528.  
  529.       if month = GetMonth then
  530.         color := clBlack;
  531.  
  532.       DrawCell(i, j, IntToStr(day), color, item = FDate, item = SysUtils.Date);
  533.     end;
  534. end;
  535.  
  536.  
  537. // TIvCalendar
  538.  
  539. constructor TIvCalendar.Create(AOwner: TComponent);
  540. var
  541.   i: Integer;
  542.   item: TMenuItem;
  543. begin
  544.   inherited Create(AOwner);
  545.  
  546.   ControlStyle := ControlStyle + [csOpaque];
  547.   Width := 100;
  548.   Height := 100;
  549.  
  550.   FTodayCaption := 'Today:';
  551.   FMargin := 4;
  552.  
  553.   { month }
  554.   FPriorMonth := TIvCalendarButton.Create(Self);
  555.   FPriorMonth.Parent := Self;
  556.   FPriorMonth.FrameState := DFCS_SCROLLLEFT;
  557.   FPriorMonth.OnClick := PriorMonthClick;
  558.  
  559.   FNextMonth := TIvCalendarButton.Create(Self);
  560.   FNextMonth.Parent := Self;
  561.   FNextMonth.FrameState := DFCS_SCROLLRIGHT;
  562.   FNextMonth.OnClick := NextMonthClick;
  563.  
  564.   FMonthMenu := TPopupMenu.Create(Self);
  565.  
  566.   for i := 1 to 12 do
  567.   begin
  568.     item := TMenuItem.Create(Self);
  569.     item.Caption := LongMonthNames[i];
  570.     item.OnClick := MonthMenuClick;
  571.     FMonthMenu.Items.Add(item);
  572.   end;
  573.  
  574.   FMonth := TLabel.Create(Self);
  575.   FMonth.Parent := Self;
  576.   FMonth.Font.Color := clWhite;
  577.   FMonth.Font.Style := [fsBold];
  578.   FMonth.Transparent := True;
  579.   FMonth.OnClick := MonthClick;
  580.  
  581.   { year }
  582.   FPriorYear := TIvCalendarButton.Create(Self);
  583.   FPriorYear.Parent := Self;
  584.   FPriorYear.FrameState := DFCS_SCROLLLEFT;
  585.   FPriorYear.OnClick := PriorYearClick;
  586.  
  587.   FNextYear := TIvCalendarButton.Create(Self);
  588.   FNextYear.Parent := Self;
  589.   FNextYear.FrameState := DFCS_SCROLLRIGHT;
  590.   FNextYear.OnClick := NextYearClick;
  591.  
  592.   FYear := TLabel.Create(Self);
  593.   FYear.Parent := Self;
  594.   FYear.AutoSize := True;
  595.   FYear.Font.Color := clWhite;
  596.   FYear.Font.Style := [fsBold];
  597.   FYear.Transparent := True;
  598.  
  599.   { grid }
  600.   FGrid := TIvCalendarGrid.Create(Self);
  601.   FGrid.Parent := Self;
  602.   FGrid.OnSelect := ValueSelect;
  603.   FGrid.OnChange := ValueChange;
  604.  
  605.   { today }
  606.   FToday := TLabel.Create(Self);
  607.   FToday.Parent := Self;
  608.   FToday.Font.Color := clBlack;
  609.   FToday.Font.Style := [fsBold];
  610.   FToday.Caption := Format('%s %s', [FTodayCaption, DateToStr(SysUtils.Date)]);
  611.   FToday.Transparent := True;
  612.   FToday.OnClick := TodayClick;
  613.  
  614.   Date := SysUtils.Date;
  615. end;
  616.  
  617. procedure TIvCalendar.SetTodayCaption(const value: String);
  618. begin
  619.   if FTodayCaption <> value then
  620.   begin
  621.     FTodayCaption := value;
  622.     if FToday <> nil then
  623.       FToday.Caption := Format('%s %s', [FTodayCaption, DateToStr(SysUtils.Date)]);
  624.   end;
  625. end;
  626.  
  627. function TIvCalendar.GetDate: TDateTime;
  628. begin
  629.   Result := FGrid.Date;
  630. end;
  631.  
  632. procedure TIvCalendar.SetDate(value: TDateTime);
  633. begin
  634.   FGrid.Date := value;
  635. end;
  636.  
  637. function TIvCalendar.GetWeek: Integer;
  638. begin
  639.   Result := FGrid.Week;
  640. end;
  641.  
  642. procedure TIvCalendar.SetWeek(value: Integer);
  643. begin
  644.   FGrid.Week := value;
  645. end;
  646.  
  647. procedure TIvCalendar.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  648. const
  649.   buttonHeight = 17;
  650.   buttonWidth = 16;
  651.   upDownWidth = 12;
  652. begin
  653.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  654.  
  655.   { year }
  656.  
  657.   if (FYear <> nil) and (FNextYear <> nil) and (FPriorYear <> nil) then
  658.   begin
  659.     FNextYear.SetBounds(
  660.       Width - FMargin - buttonWidth,
  661.       FMargin,
  662.       buttonWidth,
  663.       buttonHeight);
  664.  
  665.     FPriorYear.SetBounds(
  666.       FNextYear.Left - FYear.Width - buttonWidth - 2*FMargin,
  667.       FMargin,
  668.       buttonWidth,
  669.       buttonHeight);
  670.  
  671.     FYear.Left := FPriorYear.Left + buttonWidth + FMargin;
  672.     FYear.Top := FPriorYear.Top + (buttonHeight - FYear.Height) div 2;
  673.   end;
  674.  
  675.   { month }
  676.  
  677.   if (FMonth <> nil) and (FNextMonth <> nil) and (FPriorMonth <> nil) then
  678.   begin
  679.     FPriorMonth.SetBounds(
  680.       FMargin,
  681.       FMargin,
  682.       buttonWidth,
  683.       buttonHeight);
  684.  
  685.     FNextMonth.SetBounds(
  686.       FPriorYear.Left - buttonWidth - FMargin,
  687.       FMargin,
  688.       buttonWidth,
  689.       buttonHeight);
  690.  
  691.     FMonth.Left := FPriorMonth.Left + buttonWidth + FMargin;
  692.     FMonth.Top := FYear.Top;
  693.     FMonth.Width := FNextMonth.Left - FPriorMonth.Left - buttonWidth - 2*FMargin;
  694.   end;
  695.  
  696.   { grid }
  697.  
  698.   if FGrid <> nil then
  699.     FGrid.SetBounds(
  700.       FMargin,
  701.       3*FMargin + buttonHeight,
  702.       Width - 2*FMargin,
  703.       Height - FGrid.Top - 20);
  704.  
  705.   if FToday <> nil then
  706.   begin
  707.     FToday.Left := 30;
  708.     FToday.Top := Height - FMargin - FToday.Height;
  709.   end;
  710. end;
  711.  
  712. procedure TIvCalendar.PriorMonthClick(Sender: TObject);
  713. begin
  714.   FGrid.Month := FGrid.Month - 1;
  715. end;
  716.  
  717. procedure TIvCalendar.NextMonthClick(Sender: TObject);
  718. begin
  719.   FGrid.Month := FGrid.Month + 1;
  720. end;
  721.  
  722. procedure TIvCalendar.PriorYearClick(Sender: TObject);
  723. begin
  724.   FGrid.Year := FGrid.Year - 1;
  725. end;
  726.  
  727. procedure TIvCalendar.NextYearClick(Sender: TObject);
  728. begin
  729.   FGrid.Year := FGrid.Year + 1;
  730. end;
  731.  
  732. procedure TIvCalendar.MonthClick(Sender: TObject);
  733. begin
  734.   with ClientToScreen(Point(FMonth.Left, FMonth.Top)) do
  735.     FMonthMenu.Popup(x, y);
  736. end;
  737.  
  738. procedure TIvCalendar.MonthMenuClick(Sender: TObject);
  739. begin
  740.   FGrid.Month := (Sender as TMenuItem).MenuIndex + 1;
  741. end;
  742.  
  743. procedure TIvCalendar.TodayClick(Sender: TObject);
  744. begin
  745.   Date := SysUtils.Date;
  746. end;
  747.  
  748. procedure TIvCalendar.ValueChange(Sender: TObject);
  749. begin
  750.   FMonth.Caption := LongMonthNames[FGrid.Month];
  751.   FYear.Caption := IntToStr(FGrid.Year);
  752.   Invalidate;
  753. end;
  754.  
  755. procedure TIvCalendar.ValueSelect(Sender: TObject);
  756. begin
  757.   if Assigned(FOnSelect) then
  758.     FOnSelect(Self);
  759. end;
  760.  
  761. procedure TIvCalendar.Paint;
  762. begin
  763.   { Border }
  764.   Canvas.Pen.Color := clBlack;
  765.   Canvas.Pen.Width := 1;
  766.   Canvas.Brush.Color := clWhite;
  767.   Canvas.Brush.Style := bsSolid;
  768.   Canvas.Rectangle(0, 0, Width, Height);
  769.  
  770.   { Caption }
  771.   Canvas.Pen.Color := clNavy;
  772.   Canvas.Brush.Color := clNavy;
  773.   Canvas.Rectangle(0, 0, Width, FPriorMonth.Width + 2*FMargin);
  774.  
  775.   { Today mark }
  776.   DrawTodayMark(
  777.     Canvas,
  778.     Rect(
  779.       2*FMargin,
  780.       FToday.Top,
  781.       2*FMargin + Canvas.TextWidth('000'),
  782.       FToday.Top + Canvas.TextHeight('0')));
  783. end;
  784.  
  785.  
  786. // TIvDateTimeList
  787.  
  788. constructor TIvDateTimeList.Create(AOwner: TComponent);
  789. begin
  790.   inherited Create(AOwner);
  791.   ControlStyle := ControlStyle + [csNoDesignVisible, csReplicatable];
  792. end;
  793.  
  794. procedure TIvDateTimeList.CreateParams(var Params: TCreateParams);
  795. begin
  796.   inherited CreateParams(Params);
  797.   Params.Style := WS_POPUP;
  798.   Params.ExStyle := WS_EX_TOOLWINDOW;
  799.   Params.WindowClass.Style := CS_SAVEBITS;
  800. end;
  801.  
  802. procedure TIvDateTimeList.WMMouseActivate(var Message: TMessage);
  803. begin
  804.   Message.Result := MA_NOACTIVATE;
  805. end;
  806.  
  807.  
  808. // TIvDateTimeButton
  809.  
  810. constructor TIvDateTimeButton.Create(AOwner: TComponent);
  811. begin
  812.   inherited Create(AOwner);
  813.   FrameType := DFC_SCROLL;
  814. end;
  815.  
  816. procedure TIvDateTimeButton.MouseDown(
  817.   Button: TMouseButton;
  818.   Shift: TShiftState;
  819.   X, Y: Integer);
  820. var
  821.   edit: TIvCustomDateTimeEdit;
  822. begin
  823.   inherited MouseDown(Button, Shift, X, Y);
  824.  
  825.   if Button = mbLeft then
  826.   begin
  827.     edit := Owner as TIvCustomDateTimeEdit;
  828.  
  829.     if edit.ListVisible then
  830.     begin
  831.       edit.CloseUp(False);
  832.       Exit;
  833.     end;
  834.  
  835.     edit.DropDown;
  836.   end;
  837. end;
  838.  
  839.  
  840. // TIvCustomDateTimeEdit
  841.  
  842. constructor TIvCustomDateTimeEdit.Create(AOwner: TComponent);
  843. begin
  844.   inherited Create(AOwner);
  845.   ControlStyle := ControlStyle - [csSetCaption];
  846.   FKind := dtkDate;
  847.  
  848.   FButton := TIvDateTimeButton.Create(Self);
  849.   FButton.Parent := Self;
  850.   FButton.Width := 16;
  851.   FButton.Height := 17;
  852.   FButton.Visible := True;
  853.   FButton.FrameState := DFCS_SCROLLCOMBOBOX;
  854.  
  855.   FList := TIvDateTimeList.Create(Self);
  856.   FList.Parent := Self;
  857.   FList.Visible := False;
  858.   FList.Width := 200;
  859.   FList.Height := 160;
  860.   FList.OnSelect := ListSelect;
  861. end;
  862.  
  863. function TIvCustomDateTimeEdit.GetAsDate: TDateTime;
  864. begin
  865.   Result := StrToDate(Text);
  866. end;
  867.  
  868. procedure TIvCustomDateTimeEdit.SetAsDate(value: TDateTime);
  869. begin
  870.   Text := DateToStr(value);
  871. end;
  872.  
  873. function TIvCustomDateTimeEdit.GetAsString: String;
  874. begin
  875.   Result := Text;
  876. end;
  877.  
  878. procedure TIvCustomDateTimeEdit.SetAsString(const value: String);
  879. begin
  880.   Text := value;
  881. end;
  882.  
  883. function TIvCustomDateTimeEdit.GetListHeight: Integer;
  884. begin
  885.   Result := FList.Height;
  886. end;
  887.  
  888. procedure TIvCustomDateTimeEdit.SetListHeight(value: Integer);
  889. begin
  890.   FList.Height := value;
  891. end;
  892.  
  893. function TIvCustomDateTimeEdit.GetListWidth: Integer;
  894. begin
  895.   Result := FList.Width;
  896. end;
  897.  
  898. procedure TIvCustomDateTimeEdit.SetListWidth(value: Integer);
  899. begin
  900.   FList.Width := value;
  901. end;
  902.  
  903. procedure TIvCustomDateTimeEdit.SetKind(value: TIvDateTimeKind);
  904. begin
  905.   if FKind <> value then
  906.   begin
  907.     FKind := value;
  908.     Invalidate;
  909.   end;
  910. end;
  911.  
  912. procedure TIvCustomDateTimeEdit.CreateParams(var Params: TCreateParams);
  913. begin
  914.   inherited CreateParams(Params);
  915.   Params.Style := Params.Style or ES_MULTILINE or WS_CLIPCHILDREN;
  916. end;
  917.  
  918. procedure TIvCustomDateTimeEdit.CreateWnd;
  919. begin
  920.   inherited CreateWnd;
  921.   SetEditRect;
  922. end;
  923.  
  924. procedure TIvCustomDateTimeEdit.ListSelect(Sender: TObject);
  925. begin
  926.   CloseUp(True);
  927. end;
  928.  
  929. procedure TIvCustomDateTimeEdit.SetEditRect;
  930. var
  931.   loc: TRect;
  932. begin
  933.   SendMessage(Handle, EM_GETRECT, 0, LongInt(@loc));
  934.   loc.Bottom := ClientHeight + 1;
  935.   loc.Right := ClientWidth - FButton.Width - 2;
  936.   loc.Top := 0;
  937.   loc.Left := 0;
  938.   SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@loc));
  939. end;
  940.  
  941. procedure TIvCustomDateTimeEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  942. begin
  943.   inherited MouseDown(Button, Shift, X, Y);
  944.   CloseUp(False);
  945. end;
  946.  
  947. procedure TIvCustomDateTimeEdit.WMKillFocus(var Message: TWMKillFocus);
  948. begin
  949.   inherited;
  950.   CloseUp(False);
  951. end;
  952.  
  953. procedure TIvCustomDateTimeEdit.WMSize(var Message: TWMSize);
  954. begin
  955.   inherited;
  956.   FButton.SetBounds(Width - FButton.Width - 4, 0, FButton.Width, Height - 4);
  957.   SetEditRect;
  958. end;
  959.  
  960. procedure TIvCustomDateTimeEdit.DropDown;
  961. var
  962.   tmp: TPoint;
  963. begin
  964.   tmp := Parent.ClientToScreen(Point(Left, Top + Height));
  965.   SetFocus;
  966.   SelectAll;
  967.  
  968.   SetWindowPos(
  969.     FList.Handle,
  970.     HWND_TOP,
  971.     tmp.X,
  972.     tmp.Y,
  973.     0,
  974.     0,
  975.     SWP_NOSIZE or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  976.  
  977.   if Text <> '' then
  978.     case FKind of
  979.       dtkWeek: FList.Week := StrToInt(Text);
  980.       dtkDate: FList.Date := StrToDate(Text);
  981.       dtkTime: FList.Date := StrToTime(Text);
  982.     end;
  983.  
  984.   FListVisible := True;
  985. end;
  986.  
  987. procedure TIvCustomDateTimeEdit.SelectListValue;
  988. begin
  989.   case FKind of
  990.     dtkWeek: Text := IntToStr(FList.Week);
  991.     dtkDate: Text := DateToStr(FList.Date);
  992.     dtkTime: Text := TimeToStr(FList.Date);
  993.   end;
  994.  
  995.   SelectAll;
  996. end;
  997.  
  998. procedure TIvCustomDateTimeEdit.Clear;
  999. begin
  1000.   inherited Clear;
  1001.   FList.Date := SysUtils.Date;
  1002. end;
  1003.  
  1004. procedure TIvCustomDateTimeEdit.CloseUp(accept: Boolean);
  1005. begin
  1006.   if not ListVisible then
  1007.     Exit;
  1008.  
  1009.   SetWindowPos(
  1010.     FList.Handle,
  1011.     0,
  1012.     0,
  1013.     0,
  1014.     0,
  1015.     0,
  1016.     SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  1017.  
  1018.   FListVisible := False;
  1019.  
  1020.   if accept then
  1021.     SelectListValue;
  1022. end;
  1023.  
  1024. function TIvCustomDateTimeEdit.AcceptChar(key: Char): Boolean;
  1025.  
  1026.   function IsNumeric(key: Char): Boolean;
  1027.   begin
  1028.     Result := (key >= '0') and (key <= '9');
  1029.   end;
  1030.  
  1031. begin
  1032.   Result := True;
  1033.  
  1034.   if Key = #8 then
  1035.     Exit;
  1036.  
  1037.   case FKind of
  1038.     dtkWeek: Result := IsNumeric(key);
  1039.     dtkDate: Result := (IsNumeric(key) or (key = DateSeparator));
  1040.     dtkTime: Result := (IsNumeric(key) or (key = TimeSeparator));
  1041.   end;
  1042. end;
  1043.  
  1044. procedure TIvCustomDateTimeEdit.KeyPress(var key: Char);
  1045. begin
  1046.   inherited KeyPress(key);
  1047.  
  1048.   if (Key in [#13, #27]) and ListVisible then
  1049.   begin
  1050.     CloseUp(Key = #13);
  1051.     key := #0;
  1052.     Exit;
  1053.   end;
  1054.  
  1055.   if (Key in [#32..#255]) and not AcceptChar(key) then
  1056.   begin
  1057.     MessageBeep(0);
  1058.     key := #0;
  1059.   end;
  1060. end;
  1061.  
  1062.  
  1063. // TIvDateTimeEdit
  1064.  
  1065. constructor TIvDateTimeEdit.Create(AOwner: TComponent);
  1066. begin
  1067.   inherited Create(AOwner);
  1068. end;
  1069.  
  1070. end.
  1071.